package cn.bearspark.article.provider.service.impl;

import cn.bearspark.article.dto.category.*;
import cn.bearspark.article.provider.dao.buffer.CategoryHashBuffer;
import cn.bearspark.article.provider.dao.buffer.CategoryIdListBuffer;
import cn.bearspark.article.provider.dao.co.CategoryCO;
import cn.bearspark.article.provider.dao.mapper.CategoryMapper;
import cn.bearspark.article.provider.dao.po.category.CategoryPO;
import cn.bearspark.article.provider.service.CategoryService;
import cn.bearspark.common.aop.autoparse.host.AutoParseHost;
import cn.bearspark.common.enumeration.VisibilityEnum;
import cn.bearspark.common.util.ConvertBeanUtil;
import cn.bearspark.idgenerator.enumeration.IdCodeEnum;
import cn.bearspark.idgenerator.rpc.IdGeneratorRpc;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author f
 */
@Service
public class CategoryServiceImpl implements CategoryService {

    @DubboReference
    private IdGeneratorRpc idGeneratorRpc;

    private final CategoryMapper categoryMapper;

    private final CategoryHashBuffer categoryHashBuffer;
    private final CategoryIdListBuffer categoryIdListBuffer;

    public CategoryServiceImpl(CategoryMapper categoryMapper,
                               CategoryHashBuffer categoryHashBuffer,
                               CategoryIdListBuffer categoryIdListBuffer) {
        this.categoryMapper = categoryMapper;
        this.categoryHashBuffer = categoryHashBuffer;
        this.categoryIdListBuffer = categoryIdListBuffer;
    }

    @Override
    @AutoParseHost(AddCategoryDTO.class)
    public void add(AddCategoryDTO addCategoryDTO) {
        if (categoryIdListBuffer.isExceedRange(addCategoryDTO.getUserId())) {
            return;
        }

        long categoryId = idGeneratorRpc.generateId(IdCodeEnum.CATEGORY_ID);
        CategoryPO categoryPO = ConvertBeanUtil.convert(addCategoryDTO, CategoryPO.class);
        categoryPO.setCategoryId(categoryId);
        categoryMapper.insert(categoryPO);

        categoryIdListBuffer.clean(addCategoryDTO.getUserId());
    }

    @Override
    @AutoParseHost(CategoryDTO.class)
    public CategoryDTO get(long userId, long categoryId) {
        CategoryCO categoryCO = categoryHashBuffer.get(categoryId);
        if (categoryCO == null || categoryCO.getUserId() == null || categoryCO.getUserId() != userId) {
            return null;
        }
        return ConvertBeanUtil.convert(categoryCO, CategoryDTO.class);
    }

    @Override
    @AutoParseHost(ModifyCategoryDTO.class)
    public void modify(ModifyCategoryDTO modifyCategoryDTO) {
        if (categoryMapper.update(ConvertBeanUtil.convert(modifyCategoryDTO, CategoryPO.class)) != 0) {
            categoryHashBuffer.clean(modifyCategoryDTO.getCategoryId());
        }
    }

    @Override
    public void delete(long userId, long categoryId) {
        if (categoryMapper.delete(categoryId, userId) != 0) {
            categoryHashBuffer.clean(categoryId);
            categoryIdListBuffer.clean(userId);
        }
    }

    @Override
    public List<CategorySimpleDTO> listByListedUserId(long userId, long listedUserId) {
        List<Long> categoryIdList = categoryIdListBuffer.listCategoryId(listedUserId);
        if (categoryIdList.isEmpty()) {
            return new ArrayList<>();
        }

        // 判断是否是用户自己查看专栏分类
        boolean isSelf = userId == listedUserId;

        Map<Long, CategoryCO> categoryCOMap = categoryHashBuffer.mapSimple(categoryIdList);
        return categoryIdList.stream().map(categoryId -> {
            CategoryCO categoryCO = categoryCOMap.get(categoryId);
            CategorySimpleDTO categorySimpleDTO = ConvertBeanUtil.convert(categoryCO, CategorySimpleDTO.class);
            // 根据用户身份的不同，获取不同的分类下的专栏数量
            categorySimpleDTO.setArticleNum(isSelf ?
                    categoryCO.getAllArticleNum() :     // 如果是用户自身，则查看所有专栏数量
                    categoryCO.getPublicArticleNum());  // 否则只查看公开的专栏数量
            return categorySimpleDTO;
        }).toList();
    }

    @Override
    public boolean incrArticleNum(long userId, int visibility, List<Long> categoryIdList) {
        if (isCategoryIdInvalid(userId, categoryIdList)) {
            return false;
        }
        incrArticleNum(visibility, categoryIdList);
        return true;
    }

    @Override
    public boolean updateArticleNum(long userId, int oldVisibility, int newVisibility,
                                    List<Long> oldCategoryIdList, List<Long> newCategoryIdList) {
        if (isCategoryIdInvalid(userId, newCategoryIdList)) {
            return false;
        }
        // 减少旧分类的专栏数
        decrArticleNum(oldVisibility, oldCategoryIdList);
        // 增加新分类的专栏数
        incrArticleNum(newVisibility, newCategoryIdList);
        return true;
    }

    @Override
    public void decrArticleNum(long userId, int visibility, List<Long> categoryIdList) {
        if (isCategoryIdInvalid(userId, categoryIdList)) {
            return;
        }
        decrArticleNum(visibility, categoryIdList);
    }

    // 增加分类的专栏数
    private void incrArticleNum(int visibility, List<Long> categoryIdList) {
        if (categoryIdList.isEmpty()) {
            return;
        }
        if (visibility == VisibilityEnum.PUBLIC.getCode()) {
            // 如果专栏是 公开 的，则需要增加分类的 全部专栏数 和 公开专栏数
            categoryMapper.incrAllAndPublicArticleNum(categoryIdList);
        } else if (visibility == VisibilityEnum.PRIVATE.getCode()) {
            // 如果专栏是 私密 的，则需要增加分类的 公开专栏数
            categoryMapper.incrPublicArticleNum(categoryIdList);
        }
        categoryHashBuffer.cleanBatch(categoryIdList);
    }

    // 减少分类的专栏数
    private void decrArticleNum(int visibility, List<Long> categoryIdList) {
        if (categoryIdList.isEmpty()) {
            return;
        }
        if (visibility == VisibilityEnum.PUBLIC.getCode()) {
            // 如果专栏是 公开 的，则需要减少分类的 全部专栏数 和 公开专栏数
            categoryMapper.decrAllAndPublicArticleNum(categoryIdList);
        } else if (visibility == VisibilityEnum.PRIVATE.getCode()) {
            // 如果专栏是 私密 的，则需要减少分类的 公开专栏数
            categoryMapper.decrPublicArticleNum(categoryIdList);
        }
        categoryHashBuffer.cleanBatch(categoryIdList);
    }

    // 判断指定用户的分类 id 集合中的每个 分类是否非法
    private boolean isCategoryIdInvalid(long userId, List<Long> categoryIdList) {
        Set<Long> allCategoryIdSet = new HashSet<>(categoryIdListBuffer.listCategoryId(userId));
        Set<Long> categoryIdSet = new HashSet<>(categoryIdList);
        return !allCategoryIdSet.containsAll(categoryIdSet);
    }

    @Override
    public List<CategorySlimDTO> listSlimByCategoryId(List<Long> categoryIdList) {
        Map<Long, CategoryCO> categoryCOMap = categoryHashBuffer.mapSlim(categoryIdList);
        return categoryIdList.stream().map(categoryId ->
                ConvertBeanUtil.convert(categoryCOMap.get(categoryId), CategorySlimDTO.class)
        ).toList();
    }

    @Override
    public List<CategorySimpleDTO> listSimpleByCategoryId(List<Long> categoryIdList) {
        Map<Long, CategoryCO> categoryCOMap = categoryHashBuffer.mapSimple(categoryIdList);
        return categoryIdList.stream().map(categoryId ->
                ConvertBeanUtil.convert(categoryCOMap.get(categoryId), CategorySimpleDTO.class)
        ).toList();
    }
}
